﻿#define LOG_XMLConfig
using System;
using UnityEngine;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
namespace XmlTypes
{
	using Table = System.Collections.Generic.Dictionary<string,string>;
	using item = System.Collections.Generic.KeyValuePair<string,string>;
	using Debug = UnityEngine.Debug;
	public static class String2Instance
	{
		public static BindingFlags flags = BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.PutRefDispProperty | BindingFlags.PutDispProperty | BindingFlags.SetProperty | BindingFlags.SetField | BindingFlags.SuppressChangeType;
		private static string parseFunc = "Parse";
		private static Assembly m_assembly = null;
		private static Assembly assembly
		{
			get
			{
				if(m_assembly == null)
				{
					System.Type t = typeof(String2Instance);
					m_assembly = Assembly.GetAssembly(t);
				}
				return m_assembly;
			}
		}
		public static object Table2Instance(Type type,Dictionary<string,string> table)
		{
			object obj = Activator.CreateInstance(type);
			foreach(var item in table)
			{
				obj.Set(item.Key,item.Value,flags);
			}
			return obj;
		}
		/// <summary>
		/// 设置obj实例的name属性的值为value,查找匹配规则为flags
		/// </summary>
		/// <param name="obj">要设置的实例</param>
		/// <param name="name">要设置的属性名</param>
		/// <param name="value">要设置的值</param>
		/// <param name="flags">查找匹配规则</param>
		/// <returns></returns>
		public static int Set(this object self,string name,string value,BindingFlags flags)
		{
			try
			{
				Type insType = self.GetType();
				PropertyInfo p = insType.GetProperty(name,flags);
				if(p == null)
				{
#if LOG_XMLConfig
					Debug.LogWarningFormat("Property [{0}] function not exist in class {1}",name,insType.FullName);
#endif
					return -1;
				}
				Type propertyType = p.PropertyType;
				if(string.IsNullOrEmpty(value))
				{
#if LOG_XMLConfig
					Debug.LogWarningFormat("key = {0} value = {1} is null叫策划填写配置",name,insType.FullName);
#endif
					return -1;
				}
				#region base type
				if(propertyType == typeof(string))
				{
					p.SetValue(self,value,null);
				}
				else if(propertyType == typeof(Boolean))
				{
					bool b = (int.Parse(value) != 0);
					p.SetValue(self,b,null);
				}
				else if(propertyType.IsEnum)
				{
					System.Object ovalue = Enum.Parse(propertyType,value);
					if(Enum.IsDefined(propertyType,ovalue))
					{
						p.SetValue(self,ovalue,null);
					}
					else
					{
						Debug.LogErrorFormat("枚举{0} 没有值{1}",propertyType.FullName,value);
					}
				}
				#endregion
				#region list<>
				else if(propertyType.IsGenericType)
				{
					Type gTypeDef = propertyType.GetGenericTypeDefinition();
					if(gTypeDef == typeof(List<>))
					{
						Type genericType = propertyType.GetGenericArguments()[0];
						if(genericType == typeof(Vector3))
						{
							List<Vector3> pf = new List<Vector3>();
							string[] spv = value.Split(new char[] { '#' });
							for(int i = 0;i < spv.Length;i++)
							{
								if(spv[i].Trim() == "" || spv[i].Trim() == "0")
									continue;

								string[] sp = spv[i].Split(new char[] { ',' });
								if(sp.Length < 3)
									continue;

								Vector3 vt = new Vector3();
								float.TryParse(sp[0],out vt.x);
								float.TryParse(sp[1],out vt.y);
								float.TryParse(sp[2],out vt.z);
								pf.Add(vt);
							}
							p.SetValue(self,pf,null);
						}
						else
						{
							var lv = Activator.CreateInstance(propertyType);
							var addMethod = propertyType.GetMethod("Add");
							string[] sp = value.Split(new char[] { ',' });
							for(int i = 0;i < sp.Length;i++)
							{
								if(sp[i].Trim() != "" && sp[i].Trim() != "0")
								{
									object v = Assembly.GetExecutingAssembly().CreateInstance(genericType.FullName);
									v = Convert.ChangeType(sp[i],genericType);
									addMethod.Invoke((object)lv,new object[] { v });
								}
							}
							p.SetValue(self,lv,null);
						}
					}
				}
				#endregion
				#region other type
				else
				{
					/*
					Type[] paramsType = { typeof(string) };
					if(propertyType.IsArray)
					{
						parseFunc = "ParseArray";
						//
						Assembly ass = Assembly.GetAssembly(propertyType);
						string newtpName = propertyType.FullName.Replace("[]","");
						propertyType = ass.GetType(newtpName);
					}
					else
					{
						parseFunc = "Parse";
					}
					MethodInfo parseMethod = propertyType.GetMethod(parseFunc,paramsType);*/
					MethodInfo parseMethod = propertyType.ParseMethod();
					if(parseMethod == null)
					{
						Debug.LogErrorFormat("no method {0}",parseFunc);
					}
					else
					{
						object[] param = { value };
						object valueO = parseMethod.Invoke(parseMethod,param);
						//Debug.Log (string.Format ("set the value [{0}] is {1}", d.Key, value));
						p.SetValue(self,valueO,null);
					}
				}
				#endregion
			}
			catch(Exception e)
			{
				Debug.LogErrorFormat("parse exception key = {0} value = {1},error code ={0}",name,value,e.ToString());
				throw e;
			}
			return 1;
		}
	}
}